package org.zxp.thread.testsynchronized;

import org.junit.Test;
import org.zxp.thread.base.ThreadState;

/**
 * @program: zxp-thread-test
 * @description: ${description}
 * @author: X-Pacific zhang
 * @create: 2019-05-09 11:52
 **/
public class SynchronizedTest {
    private volatile  int a = 0;

    //加在普通方法上，锁的对象是当前类的实例
    public synchronized void  lock1()  {
        System.out.println("i am lock1");
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //加在普通方法上，锁的对象是当前类的实例，lock1运行lock2无法进入
    public synchronized void  lock2(){
        System.out.println("i am lock2");
    }


    @Test
    public void testSyncAtMethod(){
        //这个锁
        SynchronizedTest a = new SynchronizedTest();
        new Thread(a::lock1).start();
        new Thread(a::lock2).start();
        //这个不锁
        SynchronizedTest b = new SynchronizedTest();
        SynchronizedTest c = new SynchronizedTest();
        new Thread(b::lock1).start();
        new Thread(c::lock2).start();
    }

    //加在静态方法上，锁的对象类，在jvm实例中，类类型通常只有一个
    public static synchronized void slock1(){
        System.out.println("i am slock1");
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //加在静态方法上
    public static synchronized void slock2(){
        System.out.println("i am slock2");
    }

    @Test
    public void testSyncAtSMethod(){
        //这个锁
        new Thread(() -> SynchronizedTest.slock1()).start();
        new Thread(() -> SynchronizedTest.slock1()).start();
        //这个锁
        new Thread(() -> SynchronizedTest.slock1()).start();
        new Thread(() -> SynchronizedTest.slock2()).start();
        //这个锁
        SynchronizedTest b = new SynchronizedTest();
        new Thread(() -> b.slock1()).start();
        new Thread(() -> b.slock2()).start();
        //这个锁
        SynchronizedTest c = new SynchronizedTest();
        SynchronizedTest d = new SynchronizedTest();
        new Thread(() -> c.slock1()).start();
        new Thread(() -> d.slock1()).start();

        try {
            Thread.sleep(10000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testSyncAtBlock(){
        Object obj1 = new Object();
        Object obj2 = new Object();
        //锁
//        new Thread(() -> {
//            synchronized (obj1){
//                System.out.println("1");
//                try {
//                    Thread.sleep(3000L);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        }).start();
//        new Thread(() -> {
//            synchronized (obj1){
//                System.out.println("2");
//                try {
//                    Thread.sleep(3000L);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        }).start();
        //不锁
//        new Thread(() -> {
//            synchronized (obj1){
//                System.out.println("1");
//                try {
//                    Thread.sleep(3000L);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        }).start();
//        new Thread(() -> {
//            synchronized (obj2){
//                System.out.println("2");
//                try {
//                    Thread.sleep(3000L);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        }).start();
        //锁
        new Thread(() -> {
            synchronized (SynchronizedTest.class){
                    System.out.println("1");
                    try {
                        Thread.sleep(3000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
            }
        }).start();
        new Thread(() -> {
            synchronized (SynchronizedTest.class){
                System.out.println("2");
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();


        try {
            Thread.sleep(10000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    @Test
    public void testBlockState(){
        Thread thread3 = new Thread(() ->
        {
            synchronized (ThreadState.class) {
                try {
                    Thread.sleep(10000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        );
        thread3.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("thread3 `s state:" + thread3.getState());
        Thread thread4 = new Thread(() ->
        {
            synchronized (ThreadState.class) {
            }
        }
        );
        thread4.start();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("thread4 `s state:" + thread4.getState());

        try {
            Thread.sleep(10000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //测试重入锁 synchronized是可重入锁
    @Test
    public void testReenter(){
        SynchronizedTest synchronizedTest = new SynchronizedTest();
        new Thread(() -> {
            synchronizedTest.locka();
        }).start();

        try {
            Thread.sleep(5000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void locka(){
        System.out.println("locka");
        lockb();
    }

    public synchronized void lockb(){
        System.out.println("lockb");
    }

}
